package com.sheng.project.component;

import com.sheng.project.common.BasicObject;
import com.sheng.project.common.BasicRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 获取 Repository Bean
 *
 * @author by ls
 * @date 2023/8/22
 */
@Slf4j
@Component
public class Repositories implements ApplicationContextAware {

    private static final String NAMESPACE = "Repository";

    private static final Map<String, Object> CACHE = new ConcurrentHashMap<>();

    private static final Map<String, Object> CACHEDO = new ConcurrentHashMap<>();

    public static <Repository extends BasicRepository<?>> Repository get(Class<Repository> repositoryClass) {
        return (Repository) Optional.ofNullable(CACHE.get(repositoryClass.getName())).orElseThrow(() -> new RuntimeException(String.format("未找到 %S", repositoryClass.getName())));
    }

    public static <DO extends BasicObject, Repository extends BasicRepository<DO>> Repository getByDO(Class<DO> doClass) {
        // 根据实体类的类对象获取对应的 Repository Bean
        return (Repository) Optional.ofNullable(CACHEDO.get(doClass.getName())).orElseThrow(() -> new RuntimeException(String.format("未找到实体 %S 对应的 %S", doClass.getName(), NAMESPACE)));
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 查询 JpaRepository 的实现类
        applicationContext.getBeansOfType(JpaRepository.class).forEach((key, value) -> {
            Class<?> proxy = getRepositoryClassFormProxy(key, value);
            if (proxy != null) {
                ParameterizedType type = (ParameterizedType) proxy.getGenericInterfaces()[0];
                Class<?> argument = (Class<?>) type.getActualTypeArguments()[0];
                // 将对应的 JpaRepository 实现类放入 CACHE 中
                CACHE.put(proxy.getName(), value);
                // 将对应实体放入 CACHEDO 中
                CACHEDO.put(argument.getName(), value);
                log.info("获取 {} 层的 Bean：{}，VO Bean：{}", NAMESPACE, proxy.getName(), argument.getName());
            }
        });
    }

    /**
     * 获取当前类的 Repository
     *
     * @param key
     * @param o
     * @return
     */
    public Class<?> getRepositoryClassFormProxy(String key, Object o) {
        key = key.toUpperCase();
        Type[] genericInterfaces = o.getClass().getGenericInterfaces();
        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof Class) {
                String upperCase = ((Class<?>) genericInterface).getSimpleName().toUpperCase();
                if (key.equals(upperCase)) {
                    return ((Class<?>) genericInterface);
                }
            }
        }
        return null;
    }
}
